﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web.Helpers;
using System.Web.Mvc;
using System.Web.Security;
using System.Xml;
using BankCreditPortfolio.Areas.Admin.Models;
using BankCreditPortfolio.Attributes;
using BankCreditPortfolio.DAL;
using BankCreditPortfolio.DAL.Entities;
using BankCreditPortfolio.DAL.Services;
using MvcContrib.Pagination;

namespace BankCreditPortfolio.Areas.Admin.Controllers
{
    [IsAdmin]
    [ValidateInput(false)]
    public class AdminController : Controller
    {
        //
        // GET: /Admin/

        public ActionResult Index()
        {
            ViewData["Roles"] =
                (new RoleService()).CreateQuery().Where(
                    x => x.Title != "Client" && x.Title != "CreditCommitteeMember").ToList();
            ViewData["Currency"] =
                (new CurrencyService()).CreateQuery().ToList();
            ViewData["Types"] = (new DocumentTypeService()).GetAll().ToList();
            return View();
        }

        [HttpGet]
        public ActionResult AddEmployee()
        {
            ViewData["Roles"] =
                (new RoleService()).CreateQuery().Where(
                    x => x.Title != "Client").ToList();
            return View();
        }

        [HttpPost]
        public ActionResult AddEmployee(AddEmployeeModel model)
        {
            ViewData["Currency"] =
                (new CurrencyService()).CreateQuery().ToList();
            ViewData["Roles"] =
                (new RoleService()).CreateQuery().Where(
                    x => x.Title != "Client" && x.Title != "Admin").ToList();
            if (!ModelState.IsValid)
            {
                return View(model);
            }
            var accountService = new AccountService();
            var bankerService = new BankerService();
            var profileService = new ProfileService();
            var account = new Account {Email = model.Email, Role = (new RoleService()).Find(model.Role)};
            var passwordHash = PasswordHelper.Encrypt(model.Password, PasswordMode.MD5);
            account.Hash = passwordHash.Hash;
            account.Salt = passwordHash.Salt;
            var profile = new Profile
                              {
                                  Adress = model.Address,
                                  FirstName = model.FirstName,
                                  LastName = model.LastName,
                                  MiddleName = model.MiddleName,
                                  PassportDate = DateTime.Parse(model.PassportDate),
                                  PassportIssuingAuthority = model.PassportIssuingAuthority,
                                  PersonalId = model.PersonalId,
                                  Phone = model.Phone,
                                  Work = "Bank 'Dream Team'"
                              };
            var banker = new Banker {Account = account, Profile = profile};
            accountService.Save(ref account);
            profileService.Save(ref profile);
            bankerService.Save(ref banker);
            return RedirectToAction("Index");
        }

        [HttpGet]
        public ActionResult AddTariff()
        {
            ViewData["Roles"] =
                (new RoleService()).CreateQuery().Where(
                    x => x.Title != "Client" && x.Title != "CreditCommitteeMember").ToList();
            ViewData["Types"] = (new DocumentTypeService()).GetAll().ToList();
            return View(new AddTariffModel());
        }

        [HttpPost]
        public ActionResult AddTariff(string button, AddTariffModel model)
        { 
            var requestParams = this.Request.Params;
            var checkBoxesKeys = requestParams.AllKeys.Where(x => x.Contains("checkbox"));
            var tariffService = new TariffService();
            if (!ModelState.IsValid)
            {
                ViewData["Roles"] =
                    (new RoleService()).CreateQuery().Where(
                        x => x.Title != "Client" && x.Title != "CreditCommitteeMember").ToList();
                ViewData["Types"] = (new DocumentTypeService()).GetAll().ToList();
                return View(model);
            }
            var tariff = model.MapTo(new Tariff());
            foreach (var checkBoxesKey in checkBoxesKeys)
            {
                var tmp = requestParams[checkBoxesKey];
                if (tmp.Contains("true"))
                {
                    var id = checkBoxesKey.Split(new[] {"checkbox:"}, StringSplitOptions.RemoveEmptyEntries)[0];
                    var documentType = (new DocumentTypeService()).Find(Int32.Parse(id));
                    tariff.Documents.Add(documentType);
                }
            }
            tariff.Used = true;
            tariffService.Save(ref tariff);
            ViewData["Roles"] =
                (new RoleService()).CreateQuery().Where(
                    x => x.Title != "Client" && x.Title != "CreditCommitteeMember").ToList();
            ViewData["Currency"] =
                (new CurrencyService()).CreateQuery().ToList();
            return RedirectToAction("Index", "Admin");
        }

        public ActionResult ChangeTariffUsingStatatus(int tariffId)
        {
            var tariff = (new TariffService()).Find(tariffId);
            tariff.Used = !tariff.Used;
            (new TariffService()).Save(ref tariff);
            return RedirectToAction("Tariffs", "Admin");
        }

        public ActionResult Tariffs(int? page)
        {
            var tariffs = (new TariffService()).GetAll();
            IEnumerable<Tariff> tariffItems = tariffs != null ? tariffs.ToList() : new List<Tariff>();
            return View(tariffItems.AsPagination(page ?? 1, 10));
        }

        public ActionResult Tariff(int tariffId)
        {
            var tariff = (new TariffService()).Find(tariffId);
            var model = new TariffModel
            {
                Currency = tariff.Currency.Title,
                Description = tariff.Description,
                Percent = tariff.CreditPercent,
                Fine = tariff.Fine,
                Max = tariff.Max,
                Min = tariff.Min,
                FirstPayment = tariff.FirstPayment,
                OtherPayments = tariff.OtherPayments,
                RequireGuarantor = tariff.NumberOfGuarantors > 0,
                Time = tariff.Time,
                Title = tariff.Title,
                EarlyRepaimentFine = tariff.EarlyRepaymentFine,
                Used = tariff.Used
            };
            return View(model);
        }

        [HttpPost]
        public ActionResult Tariff()
        {
            return RedirectToAction("Tariffs", "Admin");
        }

        public ActionResult EditTariff(int tariffId)
        {
            var tariff = (new TariffService()).Find(tariffId);
            var model = new AddTariffModel().MapFrom(tariff);
            ViewData["Types"] = (new DocumentTypeService()).GetAll().ToList();
            return View(model);
        }

        [HttpPost]
        public ActionResult EditTariff(string submit, AddTariffModel model)
        {

            if (ModelState.IsValid)
            {
                var tariff = (new TariffService()).Find(model.TariffId);
                tariff = model.MapTo(tariff);
                var requestParams = Request.Params;
                var checkBoxesKeys = requestParams.AllKeys.Where(x => x.Contains("checkbox"));
                tariff.Documents.Clear();
                foreach (var checkBoxesKey in checkBoxesKeys)
                {
                    var tmp = requestParams[checkBoxesKey];
                    if (tmp.Contains("true"))
                    {
                        var id = checkBoxesKey.Split(new[] { "checkbox:" }, StringSplitOptions.RemoveEmptyEntries)[0];
                        var documentType = (new DocumentTypeService()).Find(Int32.Parse(id));
                        tariff.Documents.Add(documentType);
                    }
                }
                //var currencyKey = requestParams.AllKeys.Where(x => x.Contains("bbb")).First();
                //tariff.Currency = (new CurrencyService()).Find(Int32.Parse(requestParams[currencyKey]));
                (new TariffService()).Save(ref tariff);
                return RedirectToAction("Tariffs", "Admin");
            }
            ViewData["Types"] = (new DocumentTypeService()).GetAll().ToList();
            return View("EditTariff", model);
        }

        public ActionResult DeleteTariff(int tariffId)
        {
            var model = new DeleteTariffModel();
            model.TariffId = tariffId;
            var tariffService = new TariffService();
            model.TariffDescription = tariffService.Find(tariffId).Description;
            model.TariffTitle = tariffService.Find(tariffId).Title;
            return View(model);
        }

        [HttpPost]
        public ActionResult DeleteTariff(string button, DeleteTariffModel model)
        {
            var tariffService = new TariffService();
            var tariff = tariffService.Find(model.TariffId);
            var result = tariffService.Delete(tariff);
            if (result)
                return RedirectToAction("Tariffs", "Admin");
            model = new DeleteTariffModel();
            model.TariffDescription = tariff.Description;
            model.TariffTitle = tariff.Title;
            ModelState.AddModelError("", "You cannot delete this item because it is critical for correct workability of the system.");
            return View(model);
        }

        public ActionResult LogOffAdmin()
        {
            FormsAuthentication.SignOut();
            return RedirectToRoute("Global.Home");
        }

        public ActionResult AddCurrency()
        {
            return View();
        }

        [HttpPost]
        public ActionResult AddCurrency(string button, CurrencyModel model)
        {
            if ((new CurrencyService()).GetCurrencyByTitle(model.Title) != null)
            {
                ModelState.AddModelError("", "This currency is already exist.");
                return View(model);
            }
            if (ModelState.IsValid)
            {
                var currency = new Currency {Title = model.Title};
                var res = (new CurrencyService()).Save(ref currency);
                var deposit = new Deposit();
                deposit.Currency = currency;
                deposit.DepositType = (new DepositTypeService()).GetByTitle("Bank");
                deposit.Amount = 9999999999;
                deposit.Account = (new AccountService()).GetByEmail(User.Identity.Name);
                (new DepositService()).Save(ref deposit);
                if (res)
                    return RedirectToAction("Currencies", "Admin");
            }
            ModelState.AddModelError("", "This currency is not created.");
            return View(model);
        }

        public ActionResult Currencies(int? page)
        {
            var currencies = (new CurrencyService()).GetAll();
            IEnumerable<Currency> currencyItems = currencies != null ? currencies.ToList() : new List<Currency>();
            return View(currencyItems.AsPagination(page ?? 1, 10));
        }

        public ActionResult Currency(int currencyId)
        {
            var currency = (new CurrencyService()).Find(currencyId);
            var model = new CurrencyModel
            {
                Title = currency.Title
            };
            return View(model);
        }

        [HttpPost]
        public ActionResult Currency()
        {
            return RedirectToAction("Currencies", "Admin");
        }

        public ActionResult DeleteCurrency(int currencyId)
        {
            var model = new DeleteCurrencyModel();
            var tariffService = new CurrencyService();
            model.CurrencyId = currencyId;
            model.Title = tariffService.Find(currencyId).Title;
            return View(model);
        }

        [HttpPost]
        public ActionResult DeleteCurrency(string button, DeleteCurrencyModel model)
        {
            var currencyService = new CurrencyService();
            var currency = currencyService.Find(model.CurrencyId);
            var result = currencyService.Delete(currency);
            if (result)
                return RedirectToAction("Currencies", "Admin");
            model = new DeleteCurrencyModel();
            model.Title = currency.Title;
            ModelState.AddModelError("", "You cannot delete this item because it is critical for correct workability of the system.");
            return View(model);
        }

        public ActionResult AllEmployees(int? page)
        {
            var bankers = (new BankerService()).GetAll();
            IEnumerable<Banker> bankerItems = bankers != null ? bankers.ToList() : new List<Banker>();
            return View(bankerItems.AsPagination(page ?? 1, 10));
    
            //(new RoleService()).CreateQuery().Where(
            //        x => x.Title != "Client" && x.Title != "CreditCommitteeMember").ToList();


            //var bankers = (new BankerService()).CreateQuery().Where(
            //    x => x.Account.Email != string.Empty).ToList();
            //var bankerItems = bankers;
            //ViewData["Employees"] = bankerItems;
            //return View();
        }

        public ActionResult DeleteBanker(int bankerId)
        {
            var model = new DeleteBankerModel();
            var banker = (new BankerService()).Find(bankerId);
            model.BankerId = bankerId;
            model.FirstName = banker.Profile.FirstName;
            model.MiddleName = banker.Profile.MiddleName;
            model.LastName = banker.Profile.LastName;
            model.Role = banker.Account.Role.Title;
            return View(model);
        }

        [HttpPost]
        public ActionResult DeleteBanker(string button, DeleteBankerModel model)
        {
            var bankerService = new BankerService();
            var banker = bankerService.Find(model.BankerId);
            var accountService = new AccountService();
            var profileService = new ProfileService();
            var profile = banker.Profile;

            var account = banker.Account;
            account.Email = string.Empty;
            account.Hash = string.Empty;
            account.Salt = string.Empty;

            var result = accountService.Update(ref account);
            if (result)
                return RedirectToAction("AllEmployees", "Admin");
            model = new DeleteBankerModel();
            model.FirstName = banker.Profile.FirstName;
            model.BankerId = banker.BankerId;
            model.MiddleName = banker.Profile.MiddleName;
            model.LastName = banker.Profile.LastName;
            model.Role = banker.Account.Role.Title;
            ModelState.AddModelError("", "This employee is not deleted. Probably some other elements linked with this.");
            return View(model);
        }

        public  ActionResult Reports(int? creditPage, int? paymentPage)
        {
            var agreements = (new AgreementService()).GetAccepted();
            IEnumerable<Agreement> agreementItems = agreements != null ? agreements.ToList() : new List<Agreement>();
            var payments = (new PaymentService()).GetAllByStatus("Received");
            IEnumerable<Payment> paymentsItems = payments != null ? payments.ToList() : new List<Payment>();
            var model = new ReportModel { Credits = agreementItems.AsPagination(creditPage ?? 1, 10), Payments = paymentsItems.AsPagination(paymentPage ?? 1, 10) };
            return View(model);
        }

        public ActionResult CreditChart()
        {
            var periods = new List<string>();
            var amounts = new List<string>();
            var agreementsService = new AgreementService();
            for (var date = DateTime.Now.AddMonths(-12).AddDays(1-DateTime.Now.Day); date <= DateTime.Now; date = date.AddMonths(1))
            {
                periods.Add(date.ToString("MMMM yyyy"));
                amounts.Add(agreementsService.GetAmountByPeriod(date, date.AddMonths(1)).ToString());
            }
            var bytes = new Chart(width: 500, height: 600, theme: ChartTheme.Blue).AddSeries(
                chartType: "bar",
                xValue: periods,
                yValues: amounts).GetBytes("png");
            return File(bytes, "image/png");
        }

        public ActionResult PaymentChart()
        {
            var periods = new List<string>();
            var amounts = new List<string>();
            var paymentService = new PaymentService();
            for (var date = DateTime.Now.AddMonths(-12).AddDays(1-DateTime.Now.Day); date <= DateTime.Now; date = date.AddMonths(1))
            {
                periods.Add(date.ToString("MMMM yyyy"));
                amounts.Add(paymentService.GetAmountByPeriod("Received",date, date.AddMonths(1)).ToString());
            }
            var bytes = new Chart(width: 500, height: 600, theme: ChartTheme.Blue).AddSeries(
                chartType: "bar",
                xValue: periods,
                yValues: amounts).GetBytes("png");
            return File(bytes, "image/png");
        }

        public ActionResult TariffPopularityChart()
        {
            var tariffsnames = new List<string>();
            var popularity = new List<string>();
            var orders = (new OrderInfoService()).GetAll();
            var tariffs = (new TariffService()).GetAll();
            foreach (var tariff in tariffs)
            {
                var pop = orders.Count(order => order.Tariff.TariffId == tariff.TariffId);
                tariffsnames.Add(tariff.Title);
                popularity.Add(pop.ToString());
            }
            var bytes = new Chart(width: 500, height: 600, theme: ChartTheme.Blue).AddSeries(
                chartType: "bar",
                xValue: tariffsnames,
                yValues: popularity).GetBytes("png");
            return File(bytes, "image/png");
        }

        public ActionResult GetPaymentReport()
        {
            var payments = (new PaymentService()).GetAll();
            var ticks = DateTime.Now.Ticks;
            using (XmlWriter writer = XmlWriter.Create("payments" + ticks + ".xml"))
            {
                writer.WriteStartDocument();
                writer.WriteStartElement("Payments_Report" + DateTime.Now.ToString("dd_MM_yyyy"));
                foreach (var payment in payments)
                {
                    writer.WriteStartElement("Payment" + payment.PaymentId);
                    
                    writer.WriteElementString("Amount", payment.Amount.ToString("#.##"));
                    writer.WriteElementString("Currency", payment.Currency.Title);
                    writer.WriteElementString("Deposit", payment.Deposit.DepositId.ToString());
                    writer.WriteElementString("Payment_Status", payment.PaymentStatus.Title);

                    writer.WriteEndElement();
                }
                writer.WriteEndElement();
                writer.WriteEndDocument();
                writer.Close();
            }
            HttpContext.Response.AddHeader("content-disposition", "attachmen; filename=payments" + ticks + ".xml");
            HttpContext.Response.ContentType = "Text/Xml";
            return new FileStreamResult(new FileStream("payments" + ticks + ".xml", FileMode.OpenOrCreate), "Text/Xml" );
        }

        public ActionResult GetActiveCreditsReport()
        {
            var credits = (new AgreementService()).GetActive();
            IEnumerable<Agreement> creditItems = credits != null ? credits.ToList() : new List<Agreement>();
            var ticks = DateTime.Now.Ticks;
            using (XmlWriter writer = XmlWriter.Create("credits" + ticks + ".xml"))
            {
                writer.WriteStartDocument();
                writer.WriteStartElement("Payments_Report" + DateTime.Now.ToString("dd_MM_yyyy"));
                foreach (var credit in creditItems)
                {
                    writer.WriteStartElement("Payment" + credit.AgreementId);
                    writer.WriteElementString("Tariff", credit.Order.Tariff.Title);
                    writer.WriteElementString("Credit_Amount", credit.Credit.Deposit.Amount.ToString("#.##"));
                    writer.WriteElementString("Currency", credit.Credit.Deposit.Currency.Title);
                    writer.WriteElementString("Client", credit.Order.Client.Profile.FirstName + "_" + credit.Order.Client.Profile.LastName + "_" + credit.Order.Client.Profile.MiddleName);
                    writer.WriteElementString("Client_Identical_Number", credit.Order.Client.Profile.PersonalId);
                    writer.WriteElementString("BankerId", credit.Banker.BankerId.ToString());

                    writer.WriteEndElement();
                }
                writer.WriteEndElement();
                writer.WriteEndDocument();
                writer.Close();
            }
            HttpContext.Response.AddHeader("content-disposition", "attachmen; filename=credits" + ticks + ".xml");
            HttpContext.Response.ContentType = "Text/Xml";
            return new FileStreamResult(new FileStream("credits" + ticks + ".xml", FileMode.OpenOrCreate), "Text/Xml");
        }

        public ActionResult Deposits(int? page, string depType)
        {
            var deposits = depType == "client"
                               ? (new DepositService()).GetClientDeposits()
                               : (new DepositService()).GetBankDeposits();

            IEnumerable<Deposit> depositItems = deposits != null ? deposits.ToList() : new List<Deposit>();
            return View(depositItems.AsPagination(page ?? 1, 10));
        }
    }
}
